
package nsga;

public class IndividuoVRPTW implements Cloneable, Individuo
{
    private ClienteVRPTW[] clientes;
    private double[][] tiempos;
    private double capacity;
    private double tiempoInicio;
    private int[] atendidos;
    private int length;
    private CamionVRPTW[] camiones;
    private int n;
    private double[] fitness;
    private double fitnessAlgoritmo;

    public IndividuoVRPTW(ClienteVRPTW[] clientes, double[][] tiempos, double capacity)
    {
        this.clientes = clientes;
        this.tiempos = tiempos;
        this.capacity = capacity;
        this.tiempoInicio = this.clientes[0].getTiempoApertura();
        length=clientes.length-1;
        camiones=new CamionVRPTW[length];
        atendidos=new int[clientes.length];
        for(int i=0;i<atendidos.length;i++)
        {
            atendidos[i]=-1;
        }
        n=0;
    }
    
    public static IndividuoVRPTW getIndividuoGeneradoAleatoriamente(ClienteVRPTW[] clientes, double[][] tiempos, double capacity)
    {
        IndividuoVRPTW individuoVRPTW=new IndividuoVRPTW(clientes, tiempos, capacity);
        individuoVRPTW.fillWithRandomCamiones();
        isIndividuoValido(individuoVRPTW);
        return individuoVRPTW;
    }
    
    public void fillWithRandomCamiones()
    {
        while(!CamionVRPTW.allClientesTested(atendidos))
        {
            camiones[n]=CamionVRPTW.getCamionVRPTWGeneradoAleatoriamente(n, clientes, tiempos, capacity, tiempoInicio, atendidos);
            n++;
        }
    }
    
    private boolean canAddCamion(CamionVRPTW camionVRPTW)
    {
        int[] orden=camionVRPTW.getOrden();
        for(int i=1;i<orden.length;i++)
        {
            if(atendidos[orden[i]]!=-1)
            {
                return false;
            }
        }
        return true;
    }
    
    public boolean addCamion(CamionVRPTW camionVRPTW)
    {
        if(canAddCamion(camionVRPTW))
        {
            camiones[n]=camionVRPTW.clone(n, atendidos);
            n++;
            return true;
        }
        else
        {
            return false;
        }
    }
    
    public double[] getFitness()
    {
        return fitness.clone();
    }
    
    public void setFitness(double[] fitness)
    {
        this.fitness=new double[2];
        this.fitness[0]=n;
        for(int i=0;i<n;i++)
        {
            this.fitness[1]+=camiones[i].getFitness();
        }
    }
    
    public double getFitnessAlgoritmo()
    {
        return fitnessAlgoritmo;
    }

    public void setFitnessAlgoritmo(double fitnessAlgoritmo)
    {
        this.fitnessAlgoritmo = fitnessAlgoritmo;
    }
    
    public void mutar()
    {
        int rand=n-1;
        while((rand>0)&&(Math.random()<0.5))
        {
            rand--;
        }
        for(int i=rand;i<n;i++)
        {
            int[] orden=camiones[i].getOrden();
            for(int j=1;j<orden.length;j++)
            {
                atendidos[orden[j]]=-1;
            }
        }
        n=rand;
        fillWithRandomCamiones();
        isIndividuoValido(this);
    }
    
    public int[] getAtendidos()
    {
        return atendidos;
    }

    public boolean isAllClientesVisited()
    {
        return CamionVRPTW.allClientesTested(atendidos);
    }
    
    public Individuo clone()
    {
        IndividuoVRPTW individuoVRPTW=null;
        try
        {
            individuoVRPTW=(IndividuoVRPTW)super.clone();
        }
        catch(CloneNotSupportedException cloneNotSupportedException)
        {
        }
        for(int i=0;i<individuoVRPTW.n;i++)
        {
            individuoVRPTW.camiones[i]=camiones[i].clone();
        }
        individuoVRPTW.atendidos=atendidos.clone();
        individuoVRPTW.fitness=fitness.clone();
        return individuoVRPTW;
    }
    
    public CamionVRPTW[] getCamiones()
    {
        CamionVRPTW[] result=new CamionVRPTW[n];
        for(int i=0;i<result.length;i++)
        {
            result[i]=camiones[i].clone();
        }
        return result;
    }
    
    public static void isIndividuoValido(IndividuoVRPTW individuoVRPTW)
    {
        int[] prueba=new int[individuoVRPTW.atendidos.length];
        CamionVRPTW[] camiones=individuoVRPTW.getCamiones();
        for(int i=0;i<camiones.length;i++)
        {
            int[] orden=camiones[i].getOrden();
            for(int j=1;j<orden.length;j++)
            {
                if(prueba[orden[j]]>0)
                {
                    throw new Error("Individuo VRPTW invalido!!!");
                }
                else
                {
                    prueba[orden[j]]++;
                }
            }
        }
        for(int i=1;i<prueba.length;i++)
        {
            if(prueba[i]!=1)
            {
                throw new Error("Individuo VRPTW invalido!!!");
            }
        }
    }

}
